{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过柱状统计进行字符分割-1Z实验室"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "很多时候，我们要识别的字符，并不是完全独立的，它们之间可能有连笔，可能有接触点。 所以在数字识别或者整个字符识别领域，最难的难点就在于字符分割。阿凯会带大家了解字符分隔常用的几个经典算法， 包括直方图分割,CFS与传统滴水算法。\n",
    "会分三节课依次讲解。本节，我们来了解一下最简单的直方图分割。\n",
    "\n",
    "![hist_seg_result.png](hist_seg_result.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 导入图片素材"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "img = cv2.imread('demo.png', cv2.IMREAD_GRAYSCALE)\n",
    "\n",
    "plt.imshow(img, cmap=\"gray\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 垂直方向投影\n",
    "\n",
    "我们需要在垂直方向上统计白色像素点的个数（非0区域的个数）。 \n",
    "你可以使用for循环依次遍历， 但是这样比较低效， 你可以借助`numpy`的库函数，更加高效地实现。\n",
    "\n",
    "为了实现这个目的，我们需要借助 `np.nonzero` 函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([164, 164, 164, ..., 312, 312, 313]),\n",
       " array([307, 308, 309, ..., 323, 324, 322]))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.nonzero(img != 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`np.nonzero` 返回的是非0点地坐标， x轴坐标跟y坐标分别用两个`ndarray`存储。\n",
    "因为opencv中图片ndrray的格式设定， 第一维度是y轴坐标， 第二维度是x坐标。\n",
    "所以如果我们想获取图片中所有非零元素的x坐标， 需要这样\n",
    "```python\n",
    "np.nonzero(img != 0)[1]\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来我们获取了所有非零元素的x坐标的集合，当然x坐标有重复，所以需要统计个数，每个x坐标出现了多少次。\n",
    "为了滤波，我们可能需要把x坐标划分为若干个窗口(bins)，进行统计. numpy中的`np.histogram`可以实现这个功能。\n",
    "np.histogram 返回元素， 第一个为**直方图 hist**， 第二个元素为**binEdge**\n",
    "\n",
    "```python\n",
    "len(binEdge) = len(hist) + 1\n",
    "```\n",
    "\n",
    "详细使用说明见文档： [numpy.histogram](https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([  6,  12,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,   7,\n",
       "         14,  14,   7,  14,  15,   7,  15,  14,   7,  14,  15,   7,  14,\n",
       "         14,   7,  14,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,\n",
       "          7,  14,  10,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   5,  12,\n",
       "         14,   7,  14,  14,   7,  14,  15,  12,  27,  36,  25,  56,  60,\n",
       "         32,  64,  72,  36,  70,  53,  17,  27,  24,  14,  31,  42,  25,\n",
       "         68, 101,  48,  88,  70,  14,  29,  30,  15,  32,  32,  14,  24,\n",
       "         18,   9,  18,  18,   9,  17,  16,   8,  16,  14,   7,  14,  15,\n",
       "          7,  14,  14,   5,   6,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "          6,   5,  14,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,\n",
       "          7,  27,  53,  34, 107,  98,  46,  79,  28,  14,  28,  28,  14,\n",
       "         28,  28,  15,  38,  42,  21,  57,  66,  39,  80,  66, 130, 252,\n",
       "        237, 116, 128,  28,  14,  28,  28,  14,  28,  27,  12,  15,  14,\n",
       "          7,  14,  14,   7,  14,  15,   7,  14,  10,   1,   0,   0,   0,\n",
       "          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "          0,   0,  33,  57,  43, 106,  93,  45,  82,  87,  52, 104, 102,\n",
       "         45,  76,  52,  15,  28,  30,  15,  40,  59,  42, 123, 114,  53,\n",
       "         83,  41,  20,  43,  47,  35,  65,  54,  38]),\n",
       " array([ 18.        ,  19.66796875,  21.3359375 ,  23.00390625,\n",
       "         24.671875  ,  26.33984375,  28.0078125 ,  29.67578125,\n",
       "         31.34375   ,  33.01171875,  34.6796875 ,  36.34765625,\n",
       "         38.015625  ,  39.68359375,  41.3515625 ,  43.01953125,\n",
       "         44.6875    ,  46.35546875,  48.0234375 ,  49.69140625,\n",
       "         51.359375  ,  53.02734375,  54.6953125 ,  56.36328125,\n",
       "         58.03125   ,  59.69921875,  61.3671875 ,  63.03515625,\n",
       "         64.703125  ,  66.37109375,  68.0390625 ,  69.70703125,\n",
       "         71.375     ,  73.04296875,  74.7109375 ,  76.37890625,\n",
       "         78.046875  ,  79.71484375,  81.3828125 ,  83.05078125,\n",
       "         84.71875   ,  86.38671875,  88.0546875 ,  89.72265625,\n",
       "         91.390625  ,  93.05859375,  94.7265625 ,  96.39453125,\n",
       "         98.0625    ,  99.73046875, 101.3984375 , 103.06640625,\n",
       "        104.734375  , 106.40234375, 108.0703125 , 109.73828125,\n",
       "        111.40625   , 113.07421875, 114.7421875 , 116.41015625,\n",
       "        118.078125  , 119.74609375, 121.4140625 , 123.08203125,\n",
       "        124.75      , 126.41796875, 128.0859375 , 129.75390625,\n",
       "        131.421875  , 133.08984375, 134.7578125 , 136.42578125,\n",
       "        138.09375   , 139.76171875, 141.4296875 , 143.09765625,\n",
       "        144.765625  , 146.43359375, 148.1015625 , 149.76953125,\n",
       "        151.4375    , 153.10546875, 154.7734375 , 156.44140625,\n",
       "        158.109375  , 159.77734375, 161.4453125 , 163.11328125,\n",
       "        164.78125   , 166.44921875, 168.1171875 , 169.78515625,\n",
       "        171.453125  , 173.12109375, 174.7890625 , 176.45703125,\n",
       "        178.125     , 179.79296875, 181.4609375 , 183.12890625,\n",
       "        184.796875  , 186.46484375, 188.1328125 , 189.80078125,\n",
       "        191.46875   , 193.13671875, 194.8046875 , 196.47265625,\n",
       "        198.140625  , 199.80859375, 201.4765625 , 203.14453125,\n",
       "        204.8125    , 206.48046875, 208.1484375 , 209.81640625,\n",
       "        211.484375  , 213.15234375, 214.8203125 , 216.48828125,\n",
       "        218.15625   , 219.82421875, 221.4921875 , 223.16015625,\n",
       "        224.828125  , 226.49609375, 228.1640625 , 229.83203125,\n",
       "        231.5       , 233.16796875, 234.8359375 , 236.50390625,\n",
       "        238.171875  , 239.83984375, 241.5078125 , 243.17578125,\n",
       "        244.84375   , 246.51171875, 248.1796875 , 249.84765625,\n",
       "        251.515625  , 253.18359375, 254.8515625 , 256.51953125,\n",
       "        258.1875    , 259.85546875, 261.5234375 , 263.19140625,\n",
       "        264.859375  , 266.52734375, 268.1953125 , 269.86328125,\n",
       "        271.53125   , 273.19921875, 274.8671875 , 276.53515625,\n",
       "        278.203125  , 279.87109375, 281.5390625 , 283.20703125,\n",
       "        284.875     , 286.54296875, 288.2109375 , 289.87890625,\n",
       "        291.546875  , 293.21484375, 294.8828125 , 296.55078125,\n",
       "        298.21875   , 299.88671875, 301.5546875 , 303.22265625,\n",
       "        304.890625  , 306.55859375, 308.2265625 , 309.89453125,\n",
       "        311.5625    , 313.23046875, 314.8984375 , 316.56640625,\n",
       "        318.234375  , 319.90234375, 321.5703125 , 323.23828125,\n",
       "        324.90625   , 326.57421875, 328.2421875 , 329.91015625,\n",
       "        331.578125  , 333.24609375, 334.9140625 , 336.58203125,\n",
       "        338.25      , 339.91796875, 341.5859375 , 343.25390625,\n",
       "        344.921875  , 346.58984375, 348.2578125 , 349.92578125,\n",
       "        351.59375   , 353.26171875, 354.9296875 , 356.59765625,\n",
       "        358.265625  , 359.93359375, 361.6015625 , 363.26953125,\n",
       "        364.9375    , 366.60546875, 368.2734375 , 369.94140625,\n",
       "        371.609375  , 373.27734375, 374.9453125 , 376.61328125,\n",
       "        378.28125   , 379.94921875, 381.6171875 , 383.28515625,\n",
       "        384.953125  , 386.62109375, 388.2890625 , 389.95703125,\n",
       "        391.625     , 393.29296875, 394.9609375 , 396.62890625,\n",
       "        398.296875  , 399.96484375, 401.6328125 , 403.30078125,\n",
       "        404.96875   , 406.63671875, 408.3046875 , 409.97265625,\n",
       "        411.640625  , 413.30859375, 414.9765625 , 416.64453125,\n",
       "        418.3125    , 419.98046875, 421.6484375 , 423.31640625,\n",
       "        424.984375  , 426.65234375, 428.3203125 , 429.98828125,\n",
       "        431.65625   , 433.32421875, 434.9921875 , 436.66015625,\n",
       "        438.328125  , 439.99609375, 441.6640625 , 443.33203125,\n",
       "        445.        ]))"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "xhist = np.nonzero(img != 0)[1]\n",
    "\n",
    "# 获取图片高度与宽度\n",
    "height, width = img.shape\n",
    "# 定义统计窗口宽度\n",
    "bin_width = 2\n",
    "# 获取窗口数\n",
    "bins= int(width / bin_width)\n",
    "\n",
    "# 获取统计数组\n",
    "np.histogram(np.int64(xhist), bins=bins)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一个元素是我们需要的垂直方向的投影\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  6,  12,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,   7,\n",
       "        14,  14,   7,  14,  15,   7,  15,  14,   7,  14,  15,   7,  14,\n",
       "        14,   7,  14,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,\n",
       "         7,  14,  10,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   5,  12,\n",
       "        14,   7,  14,  14,   7,  14,  15,  12,  27,  36,  25,  56,  60,\n",
       "        32,  64,  72,  36,  70,  53,  17,  27,  24,  14,  31,  42,  25,\n",
       "        68, 101,  48,  88,  70,  14,  29,  30,  15,  32,  32,  14,  24,\n",
       "        18,   9,  18,  18,   9,  17,  16,   8,  16,  14,   7,  14,  15,\n",
       "         7,  14,  14,   5,   6,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "         6,   5,  14,  14,   7,  14,  14,   7,  14,  14,   7,  14,  14,\n",
       "         7,  27,  53,  34, 107,  98,  46,  79,  28,  14,  28,  28,  14,\n",
       "        28,  28,  15,  38,  42,  21,  57,  66,  39,  80,  66, 130, 252,\n",
       "       237, 116, 128,  28,  14,  28,  28,  14,  28,  27,  12,  15,  14,\n",
       "         7,  14,  14,   7,  14,  15,   7,  14,  10,   1,   0,   0,   0,\n",
       "         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "         0,   0,  33,  57,  43, 106,  93,  45,  82,  87,  52, 104, 102,\n",
       "        45,  76,  52,  15,  28,  30,  15,  40,  59,  42, 123, 114,  53,\n",
       "        83,  41,  20,  43,  47,  35,  65,  54,  38])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.histogram(np.int64(xhist), bins=bins)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def binImgHist(img, bin_width=1, direction=1):\n",
    "    '''\n",
    "        二值化图像在y轴或者x轴方向的投影统计\n",
    "    '''\n",
    "    height, width = img.shape\n",
    "    bins = None\n",
    "    if direction == 0:\n",
    "        # 在y轴方向上统计\n",
    "        bins = int(height / bin_width)\n",
    "    else:\n",
    "        bins = int(width / bin_width)\n",
    "    # 获取非零元素坐标\n",
    "    nonzero_points = np.nonzero(img != 0)\n",
    "    # 获取非零元素坐标中的x坐标集合或者y坐标集合\n",
    "    nonzero_idx_x = nonzero_points[direction]\n",
    "    #返回的统计直方图\n",
    "    hist = np.histogram(np.int64(nonzero_idx_x), bins=bins)[0]\n",
    "    \n",
    "    return hist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制x轴方向投影统计的折线图\n",
    "xhist = binImgHist(img, bin_width=1, direction=1)\n",
    "plt.plot(xhist)\n",
    "plt.show()\n",
    "# plt.savefig('digits_hist.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 检索切割点\n",
    "\n",
    "有了像素点统计之后， 我们就需要根据阈值将直方图划分为若干个片段， 从而获取到分割点。\n",
    "\n",
    "你可以调整像素最小阈值`npixel_lowerb`的大小，获得不同的分割效果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getSplitHistPoint(img, bin_width=1, direction=1, npixel_lowerb=1):\n",
    "    '''\n",
    "    获取直方图的切割点，用于切割图像\n",
    "       img 二值化图\n",
    "       bin_width: 窗口宽度\n",
    "       direction: 方向\n",
    "           0: 对\n",
    "       npixel_lowerb \n",
    "    '''\n",
    "    # 获得统计数组\n",
    "    hist = binImgHist(img, bin_width=bin_width, direction=direction)\n",
    "    # 根据是否大大于最小阈值，将hist转换为布尔类型的ndarray\n",
    "    bin_hist = hist > npixel_lowerb\n",
    "    \n",
    "    # 初始化分割点\n",
    "    split_pts = [0,]\n",
    "    bins = len(hist)\n",
    "    for bidx in range(1,bins):\n",
    "        # 检索分割点， 并添加到分割点数组\n",
    "        if bin_hist[bidx] == False and bin_hist[bidx-1] == True:\n",
    "            split_pts.append(bidx)\n",
    "    \n",
    "    if split_pts[-1] != bins-1:\n",
    "        # 添加最末尾的点\n",
    "        split_pts.append(bins-1)\n",
    "    \n",
    "    # 对分割点，进行整体放缩， 因为统计窗口bin_width可能不为1\n",
    "    split_pts = list(map(lambda x: x*bin_width,split_pts))\n",
    "    return split_pts\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获得到分割点后， 需要根据分割点，对图像进行分割"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def doSplitImgs(img, split_pts, direction=1):\n",
    "    '''\n",
    "    根据分割点对原图像进行分割\n",
    "    '''\n",
    "    n_pts = len(split_pts)\n",
    "    digits = []\n",
    "    for pidx in range(1,n_pts):\n",
    "        # 分割坐标起始点\n",
    "        startIdx = split_pts[pidx-1]\n",
    "        # 分割坐标中止点\n",
    "        endIdx = split_pts[pidx]\n",
    "        \n",
    "        if direction == 1:\n",
    "            # x轴方向\n",
    "            digits.append(img[:,startIdx:endIdx])\n",
    "        else:\n",
    "            # y轴方向\n",
    "            digits.append(img[startIdx:endIdx,:])\n",
    "            \n",
    "    return digits\n",
    "\n",
    "def displaySplitResult(digits):\n",
    "    '''\n",
    "        展示分割后的点集\n",
    "        用一个图片展示， 中间插入间隔长条（crevice_bar）\n",
    "    '''\n",
    "    # 初始化画布\n",
    "    canvas = digits[0]\n",
    "    height, width = digits[0].shape\n",
    "    # 定义分隔长条\n",
    "    crevice_bar = np.ones((height, 10)) * 200\n",
    "    \n",
    "    n_digit = len(digits)\n",
    "    for didx in range(1, n_digit):\n",
    "        # 不断拼接新的数字跟分隔长条\n",
    "        canvas = np.hstack((canvas,crevice_bar,digits[didx]))\n",
    "    \n",
    "    plt.clf()\n",
    "    plt.imshow(canvas, cmap='gray')\n",
    "    plt.show()\n",
    "    # 保存图片\n",
    "    cv2.imwrite('digit_split_by_hist.png', canvas)\n",
    "    \n",
    "split_pts = getSplitHistPoint(img, bin_width=6, direction=1, npixel_lowerb=25)\n",
    "digits = doSplitImgs(img, split_pts=split_pts, direction=1)\n",
    "displaySplitResult(digits)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 直方图分割算法总结\n",
    "\n",
    "直方图分割法比较简单粗暴，但是也有其自身存在的问题。\n",
    "\n",
    "1. 直方图分割算法比较简单暴力。 分割线必须竖直分割， 对于有一定倾斜角度的字符，它们的直方图就会连在一起，很难分割。\n",
    "2. 同时如果线条简单而且细的笔画，也很容易被割裂， 例如上图中的凡字。\n",
    "3. 如果两个字符很紧密的话， 同样也会无法识别跟分割。\n",
    "4. 对于汉字，左右分布结构， 左边的偏旁也容易跟字符主体分割开来。\n",
    "\n",
    "总之，直方图分割法，应用场景比较局限，只适用于字符内部紧凑，字间距较大的情况。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
